﻿
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace S7Communication
{
    public enum PLC_TYPE
    {
        S7_1200 = 0x01,
        S7_1500 = 0x02,
    }
    /// <summary>
    /// 控制状态
    /// </summary>
    public enum CONTROL_STATE
    {
        /// <summary>
        /// 就绪
        /// </summary>
        Ready = 0,
        /// <summary>
        /// 控制中
        /// </summary>
        Busy = 1,
        /// <summary>
        /// 完成
        /// </summary>
        Done = 2,
        /// <summary>
        /// 中止
        /// </summary>
        CommandAboted = 4,
        /// <summary>
        /// 错误
        /// </summary>
        Error = 5,
        /// <summary>
        /// 超时
        /// </summary>
        TimeOut = 6,
    }
    /// <summary>
    /// 表示层PDU类型
    /// </summary>
    public enum COTP_PDU_TYPE
    {
        /// <summary>
        /// ED Expedited Data，加急数据
        /// </summary>
        ED = 0x01,
        /// <summary>
        /// EA Expedited Data Acknowledgement，加急数据确认
        /// </summary>
        EA = 0x02,
        /// <summary>
        ///  UD，用户数据
        /// </summary>
        UD = 0x04,
        /// <summary>
        /// RJ Reject，拒绝
        /// </summary>
        RJ = 0x05,
        /// <summary>
        /// AK Data Acknowledgement，数据确认
        /// </summary>
        AK = 0x06,
        /// <summary>
        /// ER TPDU Error，TPDU错误
        /// </summary>
        ER = 0x07,
        /// <summary>
        /// DR Disconnect Request，断开请求
        /// </summary>
        DR = 0x08,
        /// <summary>
        /// DC Disconnect Confirm，断开确认
        /// </summary>
        DC = 0x0c,
        /// <summary>
        /// Connect Confirm，连接确认
        /// </summary>
        CC = 0x0d,
        /// <summary>
        /// CR Connect Request，连接请求
        /// </summary>
        CR = 0x0e,
        /// <summary>
        /// DT Data，数据传输
        /// </summary>
        DT = 0x0f
    }
    /// <summary>
    /// 数据传输作业类型
    /// </summary>
    public enum DT_ROSCTR
    {
        /// <summary>
        /// 作业请求，如，读/写存储器，读/写块，启动/停止设备，设置通信
        /// </summary>
        JOB = 0x01,
        /// <summary>
        ///确认响应，这是一个没有数据的简单确认
        /// </summary>
        ACK = 0x02,
        /// <summary>
        /// 确认数据响应，一般是响应JOB的请求
        /// </summary>
        ACK_DATA = 0x03,
        /// <summary>
        /// 原始协议的扩展，参数字段包含请求/响应ID（用于编程/调试，读取SZL，安全功能，时间设置，循环读取...）
        /// </summary>
        USERDATA = 0x07
    }
    /// <summary>
    /// 数据传输参数功能码
    /// </summary>
    public enum DT_PARAMETER_FUCTION
    {
        /// <summary>
        /// CPU服务
        /// </summary>
        CPU_Services = 0x00,
        /// <summary>
        /// 建立通信
        /// </summary>
        Setup_Communication = 0xf0,
        /// <summary>
        ///  读取值
        /// </summary>
        Read_Variable = 0x04,
        /// <summary>
        /// 写入值
        /// </summary>
        Write_Variable = 0x05,
        /// <summary>
        /// 请求下载
        /// </summary>
        Request_Download = 0x1a,
        /// <summary>
        /// 下载块
        /// </summary>
        Download_Block = 0x1b,
        /// <summary>
        /// 下载结束
        /// </summary>
        Download_Ended = 0x1c,
        /// <summary>
        /// 开始上传
        /// </summary>
        Start_Upload = 0x1d,
        /// <summary>
        /// 上传
        /// </summary>
        Upload = 0x1e,
        /// <summary>
        /// 上传结束
        /// </summary>
        End_Upload = 0x1f,
        /// <summary>
        /// 程序调用服务
        /// </summary>
        PI_Service = 0x28,
        /// <summary>
        /// 关闭PLC
        /// </summary>
        PLC_Stop = 0x29
    }
    public enum DT_DATA_SYNTAX_ID
    {
        /// <summary>
        /// S7绝对寻址-DB1.DBX10.2
        /// </summary>
        S7ANY = 0x10,
        /// <summary>
        /// R_ID for PBC
        /// </summary>
        PBC_R_ID = 0x13,
        /// <summary>
        /// Alarm lock/free dataset
        /// </summary>
        ALARM_LOCKFREE = 0x15,
        /// <summary>
        /// Alarm indication dataset
        /// </summary>
        ALARM_IND = 0x16,
        /// <summary>
        /// Alarm acknowledge message dataset
        /// </summary>
        ALARM_ACK = 0x19,
        /// <summary>
        /// Alarm query request dataset
        /// </summary>
        ALARM_QUERYREQ = 0x1a,
        /// <summary>
        /// Notify indication dataset
        /// </summary>
        NOTIFY_IND = 0x1c,
        /// <summary>
        /// seen on Drive ES Starter with routing over S7
        /// </summary>
        DRIVEESANY = 0xa2,
        /// <summary>
        /// S7符号寻址
        /// </summary>
        S7SYM = 0xb2,
        /// <summary>
        /// Kind of DB block read, seen only at an S7-400
        /// </summary>
        DBREAD = 0xb0,
        /// <summary>
        /// Sinumerik NCK HMI access
        /// </summary>
        NCK = 0x82
    }
    public enum DT_DATA_TRANSPORT_SIZI
    {
        /// <summary>
        /// 未定义
        /// </summary>
        Null = 0x00,
        /// <summary>
        /// 按位计算长度
        /// </summary>
        BIT = 0x01,
        /// <summary>
        /// 按字节计算长度
        /// </summary>
        BYTE = 0x02,
        /// <summary>
        /// bit access, 按位计算长度
        /// </summary>
        Bit = 0x03,
        /// <summary>
        /// byte/word/dword access, 按位计算长度
        /// </summary>
        Byte_Word_DWord = 0x04,
        /// <summary>
        /// integer access, 按位计算长度
        /// </summary>
        Int = 0x05,
        /// <summary>
        /// integer access, 按字节计算长度
        /// </summary>
        DInt = 0x06,
        /// <summary>
        /// real access, 按字节计算长度
        /// </summary>
        Real = 0x07,
        /// <summary>
        /// octet string, 按字节计算长度
        /// </summary>
        Octet_String = 0x09
    }
    public enum DT_DATA_AREA
    {
        /// <summary>
        /// 200系列系统信息
        /// </summary>
        SystemInfoOf200Family = 0x03,
        /// <summary>
        /// 200系列系统标志
        /// </summary>
        SystemFlagsOf200Family = 0x05,
        /// <summary>
        /// 200系列模拟量输入
        /// </summary>
        AnalogInputsOf200Family = 0x06,
        /// <summary>
        /// 200系列模拟量输出
        /// </summary>
        AnalogOutputsOf200Family = 0x07,
        /// <summary>
        /// 直接访问外设
        /// </summary>
        DirectPeripheralAccess_P = 0x80,
        /// <summary>
        /// 输入（I）
        /// </summary>
        Inputs = 0x81,
        /// <summary>
        /// 输出（Q）
        /// </summary>
        Outputs = 0x82,
        /// <summary>
        /// 内部标志（M）
        /// </summary>
        Flags = 0x83,
        /// <summary>
        /// 数据块（DB）
        /// </summary>
        DataBlocks = 0x84,
        /// <summary>
        /// 背景数据块（DI）
        /// </summary>
        InstanceDataBlocks = 0x85,
        /// <summary>
        /// 局部变量（L）
        /// </summary>
        LocalData = 0x86,
        /// <summary>
        /// 全局变量（V）
        /// </summary>
        UnknownYet = 0x87,
        /// <summary>
        /// S7计数器（C）
        /// </summary>
        S7Counters = 0x1c,
        /// <summary>
        /// S7定时器（T）
        /// </summary>
        S7Timers = 0x0d,
        /// <summary>
        /// IEC计数器（200系列）
        /// </summary>
        IEC_Counters200Family = 0x1e,
        /// <summary>
        /// IEC定时器（200系列）
        /// </summary>
        IEC_Timers200Family = 0x1f
    }
    public enum DT_RETRUN_CODE
    {
        /// <summary>
        /// 未定义，预留
        /// </summary>
        Reserved = 0x00,
        /// <summary>
        /// 硬件错误
        /// </summary>
        HardwareError = 0x01,
        /// <summary>
        /// 对象不允许访问
        /// </summary>
        AccessingNotAllowed = 0x03,
        /// <summary>
        /// 无效地址，所需的地址超出此PLC的极限
        /// </summary>
        InvalidAddress = 0x05,
        /// <summary>
        /// 数据类型不支持
        /// </summary>
        DataTypeNotSupported = 0x06,
        /// <summary>
        /// 日期类型不一致
        /// </summary>
        DateTypeInconsistent = 0x07,
        /// <summary>
        /// 对象不存在
        /// </summary>
        ObjectNnotExist = 0x0a,
        /// <summary>
        /// 成功
        /// </summary>
        Success = 0xff
    }
    public enum VARIABLE_TYPE
    {
        /// <summary>
        /// 1位布尔型
        /// </summary>
        Bool = 0x00,
        /// <summary>
        /// 8位字节
        /// </summary>
        Byte = 0x01,
        /// <summary>
        /// 16位字
        /// </summary>
        Word = 0x02,
        /// <summary>
        /// 16位整型
        /// </summary>
        Int = 0x03,
        /// <summary>
        /// 16位无符号整型
        /// </summary>
        UInt = 0x04,
        /// <summary>
        /// 32位双字
        /// </summary>
        DWord = 0x05,
        /// <summary>
        /// 32位整型
        /// </summary>
        DInt = 0x06,
        /// <summary>
        /// 32位无符号整型
        /// </summary>
        UDInt = 0x07,
        /// <summary>
        /// 32位浮点型
        /// </summary>
        Real = 0x08,
        /// <summary>
        /// 64位长整型
        /// </summary>
        LInt = 0x09,
        /// <summary>
        /// 64位无符号长整型
        /// </summary>
        ULInt = 0x0a,
        /// <summary>
        /// 64位浮点型
        /// </summary>
        LReal = 0x0b,
        /// <summary>
        /// 字符串
        /// </summary>
        String = 0x0c,
    }
    public class AnalysisData
    {
        /// <summary>
        /// 版本号
        /// </summary>
        public byte tpkt_version;
        /// <summary>
        /// 预留
        /// </summary>
        public byte tpkt_reserve;
        /// <summary>
        /// 数据总长度
        /// </summary>
        public ushort tpkt_length;
        /// <summary>
        /// 表示层数据长度
        /// </summary>
        public byte cotp_length;
        /// <summary>
        /// 表示层pdu类型
        /// </summary>
        public COTP_PDU_TYPE cotp_pduType;
        /// <summary>
        /// 目标引用，唯一标识
        /// </summary>
        public ushort cotp_destinationRef;
        /// <summary>
        /// 源引用，唯一标识
        /// </summary>
        public ushort cotp_sourcenRef;
        /// <summary>
        /// 扩展格式/流控制
        /// </summary>
        public byte cotp_opt;
        /// <summary>
        /// 机架号
        /// </summary>
        public ushort cotp_rack;
        /// <summary>
        /// 槽号
        /// </summary>
        public ushort cotp_solt;
        /// <summary>
        /// 参数组数量
        /// </summary>
        public ushort cotp_paramsCount;
        /// <summary>
        ///参数组
        /// </summary>
        public List<COTP_Parameter> cotp_parameters;

        /// <summary>
        /// 协议ID，通常为0x32
        /// </summary>
        public byte dt_header_protocolID;
        /// <summary>
        ///   
        /// </summary>
        public DT_ROSCTR dt_header_roscrt;
        /// <summary>
        /// 预留
        /// </summary>
        public ushort dt_header_reserve;
        /// <summary>
        /// 应答序列
        /// </summary>
        public ushort dt_header_sequenceID;
        /// <summary>
        /// 参数长度
        /// </summary>
        public ushort dt_header_paramLength;
        /// <summary>
        /// 数据长度
        /// </summary>
        public ushort dt_header_dataLength;
        /// <summary>
        /// 错误等级
        /// 0x00:没有错误
        /// 0x81:应用关系
        /// 0x82:对象定义
        /// 0x83:没有可用资源
        /// 0x84:服务处理中错误
        /// 0x85:请求错误
        /// 0x87:访问错误
        /// </summary>
        public byte dt_header_errorClass;
        /// <summary>
        /// 错误代码,未定义
        /// </summary>
        public byte dt_header_errorCode;
        /// <summary>
        /// 数据传输功能码
        /// 0x00：CPU服务
        /// 0xf0：建立通信
        /// 0x04：读取值
        /// 0x05：写入值
        /// 0x1a：请求下载
        /// 0x1b：下载块
        /// 0x1c：下载结束
        /// 0x1d：开始上传
        /// 0x1e：上传
        /// 0x1f：上传结束
        /// 0x28：程序调用服务
        /// 0x29：关闭PLC
        /// </summary>
        public DT_PARAMETER_FUCTION dt_parameter_function;
        /// <summary>
        /// item数量
        /// </summary>
        public byte dt_parameter_itemCount;
        /// <summary>
        /// 调用的最大并行作业数
        /// </summary>
        public ushort dt_stepCommunication_maxAmQCalling;
        /// <summary>
        /// 已调用的最大并行作业数
        /// </summary>
        public ushort dt_stepCommunication_maxAmQCalled;
        /// <summary>
        /// 协商pdu长度
        /// </summary>
        public ushort dt_stepCommunication_pduLength;
        /// <summary>
        /// item内容
        /// </summary>
        public List<AckItem> dt_items;

        public AnalysisData()
        {
            cotp_parameters=new List<COTP_Parameter> ();
            dt_items=new List<AckItem> ();
        }
    }
    public struct COTP_Parameter
    {
        /// <summary>
        /// 参数代码
        /// 0xc0：TPDU-Size
        /// 0xc1：源节点
        /// 0xc2：目标节点
        /// </summary>
        public byte paramCode;
        /// <summary>
        /// 参数长度
        /// </summary>
        public byte paramLength;
        /// <summary>
        /// 参数内容
        /// </summary>
        public byte[] param;
    }
    public struct Variable
    {
        /// <summary>
        /// 变量名称
        /// </summary>
        public string name;
        /// <summary>
        /// 数据类型
        /// </summary>
        public VARIABLE_TYPE dateType;
        /// <summary>
        /// 数量=1为单个变量，大于1为数组
        /// </summary>
        public int Count;
        /// <summary>
        /// 确定项目结构的主要类型，通常为0x12，代表变量规范
        /// </summary>
        public byte specificationType;
        /// <summary>
        /// 本Item其余部分的长度
        /// </summary>
        public byte itemLength;
        /// <summary>
        /// 即IDS 的地址规范的格式类型，用于确定寻址模式和其余项目结构的格式     
        /// 0x10:指针寻址
        /// 0xb2:符号寻址
        /// </summary>
        public DT_DATA_SYNTAX_ID syntaxId;
        /// <summary>
        /// 数据传输大小
        /// 0：Null
        /// 1：按位为单位
        /// 2：按字为单位
        /// 3：Bit通道，按bit为单位计算长度
        /// 4：BYTE/WORD/DWORD通道，按bit为单位计算长度
        /// 5：INT通道，按bit为单位计算长度
        /// 6：DINT,按byte为单位计算长度
        /// 7：REAL，按byte为单位计算长度
        /// 9：TRING，按byte为单位计算长度
        /// </summary>
        public DT_DATA_TRANSPORT_SIZI transportSizes;
        /// <summary>
        /// 请求数据的长度
        /// </summary>
        public ushort dataLength;
        /// <summary>
        /// DB模块的编号，如果访问的不是DB区域，此处为0x0000
        /// </summary>
        public ushort dbNumber;
        /// <summary>
        /// 区域类型
        /// 0x81:输入（I）
        /// 0x82:输出（Q）
        /// 0x83:内部标志（M）
        /// 0x84:数据块（DB）
        /// </summary>
        public DT_DATA_AREA area;
        /// <summary>
        /// 地址偏移量，根据syntaxID确认偏移值，3个字节长度
        /// </summary>
        public int adrress;
        /// <summary>
        /// 返回结果
        /// </summary>
        public DT_RETRUN_CODE returnCode;
        /// <summary>
        /// 写入数据
        /// </summary>
        public byte[] data;
    }
    public struct AckItem
    {
        /// <summary>
        /// 返回码
        /// </summary>
        public DT_RETRUN_CODE returnCode;
        /// <summary>
        /// 数据传输大小
        /// 0：Null
        /// 1：按位为单位
        /// 2：按字为单位
        /// 3：Bit通道，按bit为单位计算长度
        /// 4：BYTE/WORD/DWORD通道，按bit为单位计算长度
        /// 5：INT通道，按bit为单位计算长度
        /// 6：DINT,按byte为单位计算长度
        /// 7：REAL，按byte为单位计算长度
        /// 9：TRING，按byte为单位计算长度
        /// </summary>
        public DT_DATA_TRANSPORT_SIZI transportSizes;
        /// <summary>
        /// 返回数据的长度
        /// </summary>
        public ushort dataLength;
        /// <summary>
        /// 数据
        /// </summary>
        public byte[] data;
    }
}
